package com.beauty.inventory.service.impl;

import com.beauty.inventory.dto.InventoryRequest;
import com.beauty.inventory.dto.InventoryResponse;
import com.beauty.inventory.entity.Inventory;
import com.beauty.inventory.exception.InsufficientStockException;
import com.beauty.inventory.exception.InventoryException;
import com.beauty.inventory.repository.InventoryRepository;
import com.beauty.inventory.service.DistributedLockService;
import com.beauty.inventory.service.InventoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.persistence.EntityNotFoundException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class InventoryServiceImpl implements InventoryService {
    
    private final InventoryRepository inventoryRepository;
    private final DistributedLockService lockService;
    
    private static final String INVENTORY_LOCK_PREFIX = "inventory:lock:";
    private static final long LOCK_WAIT_TIME = 5;
    private static final long LOCK_LEASE_TIME = 10;

    @Override
    @Transactional
    public InventoryResponse createInventory(InventoryRequest inventoryRequest) {
        // 检查产品是否已经存在库存
        if (inventoryRepository.findByProductId(inventoryRequest.getProductId()).isPresent()) {
            throw new InventoryException("产品已存在库存记录: " + inventoryRequest.getProductId());
        }
        
        Inventory inventory = new Inventory();
        inventory.setProductId(inventoryRequest.getProductId());
        inventory.setQuantity(inventoryRequest.getQuantity());
        inventory.setReservedQuantity(inventoryRequest.getReservedQuantity());
        inventory.setSafetyStock(inventoryRequest.getSafetyStock());
        inventory.setWarehouseId(inventoryRequest.getWarehouseId());
        inventory.setLocation(inventoryRequest.getLocation());
        inventory.setBatchNumber(inventoryRequest.getBatchNumber());
        inventory.setExpiryDate(inventoryRequest.getExpiryDate());
        
        Inventory savedInventory = inventoryRepository.save(inventory);
        return InventoryResponse.fromEntity(savedInventory);
    }
    
    @Override
    public InventoryResponse getInventoryById(Long id) {
        Inventory inventory = inventoryRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("库存记录不存在，ID: " + id));
        return InventoryResponse.fromEntity(inventory);
    }
    
    @Override
    public InventoryResponse getInventoryByProductId(String productId) {
        Inventory inventory = inventoryRepository.findByProductId(productId)
                .orElseThrow(() -> new EntityNotFoundException("产品库存记录不存在: " + productId));
        return InventoryResponse.fromEntity(inventory);
    }
    
    @Override
    public InventoryResponse getProductInventory(String productId) {
        log.info("【库存服务】获取产品[{}]库存信息", productId);
        return getInventoryByProductId(productId);
    }
    
    @Override
    public List<InventoryResponse> getInventoriesByWarehouseId(String warehouseId) {
        return inventoryRepository.findByWarehouseId(warehouseId)
                .stream()
                .map(InventoryResponse::fromEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<InventoryResponse> getLowStockItems() {
        return inventoryRepository.findLowStockItems()
                .stream()
                .map(InventoryResponse::fromEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<InventoryResponse> getAvailableItems() {
        return inventoryRepository.findAvailableItems()
                .stream()
                .map(InventoryResponse::fromEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<InventoryResponse> getAllInventories() {
        return inventoryRepository.findAll()
                .stream()
                .map(InventoryResponse::fromEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional
    public InventoryResponse updateInventory(Long id, InventoryRequest inventoryRequest) {
        Inventory inventory = inventoryRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("库存记录不存在，ID: " + id));
        
        // 如果更改了产品ID，需要确保新的产品ID不存在
        if (!inventory.getProductId().equals(inventoryRequest.getProductId()) &&
                inventoryRepository.findByProductId(inventoryRequest.getProductId()).isPresent()) {
            throw new InventoryException("产品已存在库存记录: " + inventoryRequest.getProductId());
        }
        
        inventory.setProductId(inventoryRequest.getProductId());
        inventory.setQuantity(inventoryRequest.getQuantity());
        inventory.setReservedQuantity(inventoryRequest.getReservedQuantity());
        inventory.setSafetyStock(inventoryRequest.getSafetyStock());
        inventory.setWarehouseId(inventoryRequest.getWarehouseId());
        inventory.setLocation(inventoryRequest.getLocation());
        inventory.setBatchNumber(inventoryRequest.getBatchNumber());
        inventory.setExpiryDate(inventoryRequest.getExpiryDate());
        
        Inventory updatedInventory = inventoryRepository.save(inventory);
        return InventoryResponse.fromEntity(updatedInventory);
    }
    
    @Override
    @Transactional
    public void deleteInventory(Long id) {
        if (!inventoryRepository.existsById(id)) {
            throw new EntityNotFoundException("库存记录不存在，ID: " + id);
        }
        inventoryRepository.deleteById(id);
    }
    
    @Override
    @Transactional
    public InventoryResponse addStock(String productId, Integer quantity) {
        if (quantity <= 0) {
            throw new IllegalArgumentException("添加的库存数量必须大于0");
        }
        
        Inventory inventory = inventoryRepository.findByProductId(productId)
                .orElseThrow(() -> new EntityNotFoundException("产品库存记录不存在: " + productId));
        
        inventory.setQuantity(inventory.getQuantity() + quantity);
        
        Inventory updatedInventory = inventoryRepository.save(inventory);
        return InventoryResponse.fromEntity(updatedInventory);
    }
    
    @Override
    @Transactional
    public InventoryResponse reduceStock(String productId, Integer quantity) {
        String lockKey = INVENTORY_LOCK_PREFIX + productId;
        
        try {
            return lockService.executeWithLock(lockKey, LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS, () -> {
                log.info("【库存服务】开始减少产品[{}]库存，数量: {}", productId, quantity);
                
                Inventory inventory = inventoryRepository.findByProductId(productId)
                        .orElseThrow(() -> new EntityNotFoundException("产品库存不存在，产品ID: " + productId));
                
                // 检查库存是否充足
                if (inventory.getQuantity() < quantity) {
                    log.error("【库存服务】产品[{}]库存不足，当前库存: {}, 需要: {}", 
                            productId, inventory.getQuantity(), quantity);
                    throw new InsufficientStockException("产品库存不足，产品ID: " + productId);
                }
                
                // 检查预留库存是否充足
                if (inventory.getReservedQuantity() < quantity) {
                    log.error("【库存服务】产品[{}]预留库存不足，当前预留: {}, 需要扣减: {}", 
                            productId, inventory.getReservedQuantity(), quantity);
                    throw new InsufficientStockException("产品预留库存不足，产品ID: " + productId);
                }
                
                // 减少总库存和预留库存
                inventory.setQuantity(inventory.getQuantity() - quantity);
                inventory.setReservedQuantity(inventory.getReservedQuantity() - quantity);
                
                Inventory updatedInventory = inventoryRepository.save(inventory);
                log.info("【库存服务】产品[{}]库存减少成功，当前库存: 总={}, 已预留={}, 可用={}",
                        productId, updatedInventory.getQuantity(), updatedInventory.getReservedQuantity(), 
                        updatedInventory.getAvailableQuantity());
                
                return InventoryResponse.fromEntity(updatedInventory);
            });
        } catch (InterruptedException e) {
            log.error("【库存服务】减少库存过程被中断，productId: {}", productId, e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("减少库存操作被中断");
        }
    }
    
    @Override
    @Transactional
    public InventoryResponse reserveStock(String productId, Integer quantity) {
        String lockKey = INVENTORY_LOCK_PREFIX + productId;
        
        try {
            return lockService.executeWithLock(lockKey, LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS, () -> {
                log.info("【库存服务】开始预留产品[{}]库存，数量: {}", productId, quantity);
                
                Inventory inventory = inventoryRepository.findByProductId(productId)
                        .orElseThrow(() -> new EntityNotFoundException("产品库存不存在，产品ID: " + productId));
                
                // 检查可用库存
                if (inventory.getAvailableQuantity() < quantity) {
                    log.error("【库存服务】产品[{}]库存不足，当前可用: {}, 需要: {}", 
                            productId, inventory.getAvailableQuantity(), quantity);
                    throw new InsufficientStockException("产品库存不足，产品ID: " + productId);
                }
                
                // 增加预留库存
                inventory.setReservedQuantity(inventory.getReservedQuantity() + quantity);
                
                Inventory updatedInventory = inventoryRepository.save(inventory);
                log.info("【库存服务】产品[{}]库存预留成功，当前库存: 总={}, 已预留={}, 可用={}",
                        productId, updatedInventory.getQuantity(), updatedInventory.getReservedQuantity(), 
                        updatedInventory.getAvailableQuantity());
                
                return InventoryResponse.fromEntity(updatedInventory);
            });
        } catch (InterruptedException e) {
            log.error("【库存服务】预留库存过程被中断，productId: {}", productId, e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("预留库存操作被中断");
        }
    }
    
    @Override
    @Transactional
    public InventoryResponse releaseReservedStock(String productId, Integer quantity) {
        String lockKey = INVENTORY_LOCK_PREFIX + productId;
        
        try {
            return lockService.executeWithLock(lockKey, LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS, () -> {
                log.info("【库存服务】开始释放产品[{}]预留库存，数量: {}", productId, quantity);
                
                Inventory inventory = inventoryRepository.findByProductId(productId)
                        .orElseThrow(() -> new EntityNotFoundException("产品库存不存在，产品ID: " + productId));
                
                // 检查预留库存是否充足
                if (inventory.getReservedQuantity() < quantity) {
                    log.error("【库存服务】产品[{}]预留库存不足，当前预留: {}, 需释放: {}", 
                            productId, inventory.getReservedQuantity(), quantity);
                    throw new InsufficientStockException("产品预留库存不足，产品ID: " + productId);
                }
                
                // 减少预留库存
                inventory.setReservedQuantity(inventory.getReservedQuantity() - quantity);
                
                Inventory updatedInventory = inventoryRepository.save(inventory);
                log.info("【库存服务】产品[{}]预留库存释放成功，当前库存: 总={}, 已预留={}, 可用={}",
                        productId, updatedInventory.getQuantity(), updatedInventory.getReservedQuantity(), 
                        updatedInventory.getAvailableQuantity());
                
                return InventoryResponse.fromEntity(updatedInventory);
            });
        } catch (InterruptedException e) {
            log.error("【库存服务】释放预留库存过程被中断，productId: {}", productId, e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("释放预留库存操作被中断");
        }
    }
    
    @Override
    @Transactional
    public InventoryResponse increaseStock(String productId, Integer quantity) {
        String lockKey = INVENTORY_LOCK_PREFIX + productId;
        
        try {
            return lockService.executeWithLock(lockKey, LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS, () -> {
                log.info("【库存服务】开始增加产品[{}]库存，数量: {}", productId, quantity);
                
                Inventory inventory = inventoryRepository.findByProductId(productId)
                        .orElseThrow(() -> new EntityNotFoundException("产品库存不存在，产品ID: " + productId));
                
                // 增加总库存
                inventory.setQuantity(inventory.getQuantity() + quantity);
                
                Inventory updatedInventory = inventoryRepository.save(inventory);
                log.info("【库存服务】产品[{}]库存增加成功，当前库存: 总={}, 已预留={}, 可用={}",
                        productId, updatedInventory.getQuantity(), updatedInventory.getReservedQuantity(), 
                        updatedInventory.getAvailableQuantity());
                
                return InventoryResponse.fromEntity(updatedInventory);
            });
        } catch (InterruptedException e) {
            log.error("【库存服务】增加库存过程被中断，productId: {}", productId, e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("增加库存操作被中断");
        }
    }
} 